/**
 * Quadtree 使用示例（适配 Cocos Creator 3.8）
 * 
 * @description
 * 演示如何在 Cocos Creator 3.8 中使用四叉树进行碰撞检测
 */

import { _decorator, Component, Vec3, Graphics, Color, game } from 'cc';
import { Quadtree, Rectangle, Circle, Line } from './index';
import { Log } from '../logger/LoggerGlobal';

const { ccclass, property } = _decorator;

/**
 * 游戏实体（带四叉树索引）
 */
class GameEntity extends Rectangle<{ name: string; health: number }> {
    velocity: Vec3 = new Vec3();
    
    constructor(x: number, y: number, width: number, height: number, name: string) {
        super({
            x,
            y,
            width,
            height,
            data: { name, health: 100 }
        });
    }
    
    /**
     * 更新位置
     */
    updatePosition(dt: number): void {
        this.x += this.velocity.x * dt;
        this.y += this.velocity.y * dt;
    }
}

/**
 * 四叉树示例组件
 */
@ccclass('QuadtreeExample')
export class QuadtreeExample extends Component {
    
    @property(Graphics)
    graphics: Graphics | null = null;
    
    /** 四叉树 */
    private quadtree: Quadtree<GameEntity> | null = null;
    
    /** 游戏实体列表 */
    private entities: GameEntity[] = [];
    
    /** 碰撞对 */
    private collisionPairs: Set<string> = new Set();
    
    /** 统计信息 */
    private stats = {
        entityCount: 0,
        collisionChecks: 0,
        collisions: 0,
        updateTime: 0,
        renderTime: 0
    };
    
    onLoad(): void {
        Log.ecs.info('QuadtreeExample 初始化');
        
        // 创建四叉树
        this.quadtree = new Quadtree<GameEntity>({
            width: 800,
            height: 600,
            x: -400,
            y: -300,
            maxObjects: 10,
            maxLevels: 4
        });
        
        // 创建测试实体
        this.createEntities(50);
        
        // 初始化 Graphics
        if (!this.graphics) {
            this.graphics = this.node.addComponent(Graphics);
        }
    }
    
    /**
     * 创建测试实体
     */
    private createEntities(count: number): void {
        for (let i = 0; i < count; i++) {
            const entity = new GameEntity(
                Math.random() * 800 - 400,
                Math.random() * 600 - 300,
                20 + Math.random() * 30,
                20 + Math.random() * 30,
                `Entity_${i}`
            );
            
            // 随机速度
            entity.velocity.set(
                (Math.random() - 0.5) * 200,
                (Math.random() - 0.5) * 200,
                0
            );
            
            this.entities.push(entity);
        }
        
        this.stats.entityCount = count;
        Log.ecs.info(`创建了 ${count} 个实体`);
    }
    
    update(dt: number): void {
        if (!this.quadtree || !this.graphics) {
            return;
        }
        
        const startTime = performance.now();
        
        // 1. 清空四叉树
        this.quadtree.clear();
        
        // 2. 更新所有实体位置
        for (const entity of this.entities) {
            entity.updatePosition(dt);
            
            // 边界反弹
            if (entity.x < -400 || entity.x + entity.width > 400) {
                entity.velocity.x *= -1;
                entity.x = Math.max(-400, Math.min(400 - entity.width, entity.x));
            }
            if (entity.y < -300 || entity.y + entity.height > 300) {
                entity.velocity.y *= -1;
                entity.y = Math.max(-300, Math.min(300 - entity.height, entity.y));
            }
            
            // 插入到四叉树
            this.quadtree.insert(entity);
        }
        
        // 3. 碰撞检测
        this.detectCollisions();
        
        this.stats.updateTime = performance.now() - startTime;
        
        // 4. 渲染
        this.render();
    }
    
    /**
     * 碰撞检测
     */
    private detectCollisions(): void {
        if (!this.quadtree) return;
        
        this.collisionPairs.clear();
        this.stats.collisionChecks = 0;
        this.stats.collisions = 0;
        
        for (const entity of this.entities) {
            // 查询可能碰撞的实体
            const candidates = this.quadtree.retrieve(entity);
            
            // 精确碰撞检测
            for (const other of candidates) {
                if (entity === other) continue;
                
                this.stats.collisionChecks++;
                
                if (this.checkCollision(entity, other)) {
                    // 记录碰撞对（避免重复）
                    const pairId = this.getCollisionPairId(entity, other);
                    if (!this.collisionPairs.has(pairId)) {
                        this.collisionPairs.add(pairId);
                        this.stats.collisions++;
                        
                        // 碰撞响应（简单弹开）
                        this.resolveCollision(entity, other);
                    }
                }
            }
        }
    }
    
    /**
     * 检测两个矩形是否碰撞（AABB）
     */
    private checkCollision(a: Rectangle, b: Rectangle): boolean {
        return !(
            a.x + a.width < b.x ||
            a.x > b.x + b.width ||
            a.y + a.height < b.y ||
            a.y > b.y + b.height
        );
    }
    
    /**
     * 获取碰撞对 ID
     */
    private getCollisionPairId(a: GameEntity, b: GameEntity): string {
        const idA = a.data?.name || '';
        const idB = b.data?.name || '';
        return idA < idB ? `${idA}_${idB}` : `${idB}_${idA}`;
    }
    
    /**
     * 碰撞响应
     */
    private resolveCollision(a: GameEntity, b: GameEntity): void {
        // 简单的速度交换
        const tempVx = a.velocity.x;
        const tempVy = a.velocity.y;
        
        a.velocity.x = b.velocity.x;
        a.velocity.y = b.velocity.y;
        
        b.velocity.x = tempVx;
        b.velocity.y = tempVy;
        
        // 减少生命值
        if (a.data) a.data.health -= 1;
        if (b.data) b.data.health -= 1;
    }
    
    /**
     * 渲染
     */
    private render(): void {
        if (!this.graphics || !this.quadtree) return;
        
        const startTime = performance.now();
        
        this.graphics.clear();
        
        // 绘制四叉树网格
        this.drawQuadtree(this.quadtree);
        
        // 绘制实体
        for (const entity of this.entities) {
            const color = entity.data && entity.data.health < 50 
                ? Color.RED 
                : Color.GREEN;
            
            this.graphics.strokeColor = color;
            this.graphics.lineWidth = 2;
            this.graphics.rect(entity.x, entity.y, entity.width, entity.height);
            this.graphics.stroke();
        }
        
        this.stats.renderTime = performance.now() - startTime;
        
        // 每 60 帧打印一次统计信息
        if (game.totalFrames % 60 === 0) {
            this.printStats();
        }
    }
    
    /**
     * 递归绘制四叉树节点
     */
    private drawQuadtree(tree: Quadtree<GameEntity>): void {
        if (!this.graphics) return;
        
        // 绘制节点边界
        this.graphics.strokeColor = Color.GRAY;
        this.graphics.lineWidth = 1;
        this.graphics.rect(
            tree.bounds.x,
            tree.bounds.y,
            tree.bounds.width,
            tree.bounds.height
        );
        this.graphics.stroke();
        
        // 递归绘制子节点
        for (const node of tree.nodes) {
            this.drawQuadtree(node);
        }
    }
    
    /**
     * 打印统计信息
     */
    private printStats(): void {
        Log.performance.info('四叉树性能统计', {
            实体数量: this.stats.entityCount,
            碰撞检测次数: this.stats.collisionChecks,
            碰撞数量: this.stats.collisions,
            更新耗时: `${this.stats.updateTime.toFixed(2)}ms`,
            渲染耗时: `${this.stats.renderTime.toFixed(2)}ms`,
            总耗时: `${(this.stats.updateTime + this.stats.renderTime).toFixed(2)}ms`,
            优化率: `${((1 - this.stats.collisionChecks / (this.stats.entityCount * this.stats.entityCount)) * 100).toFixed(1)}%`
        });
    }
    
    onDestroy(): void {
        if (this.quadtree) {
            this.quadtree.clear();
        }
        this.entities = [];
        this.collisionPairs.clear();
        
        Log.ecs.info('QuadtreeExample 已销毁');
    }
}

/**
 * 四叉树基础使用示例
 */
export class QuadtreeBasicExamples {
    
    /**
     * 示例 1: 基础矩形碰撞检测
     */
    static example1_BasicRectangles(): void {
        Log.ecs.info('=== 示例 1: 基础矩形碰撞检测 ===');
        
        // 创建四叉树
        const tree = new Quadtree<Rectangle>({
            width: 100,
            height: 100,
            x: 0,
            y: 0
        });
        
        // 插入矩形
        const rect1 = new Rectangle({ x: 10, y: 10, width: 20, height: 20 });
        const rect2 = new Rectangle({ x: 50, y: 50, width: 20, height: 20 });
        const rect3 = new Rectangle({ x: 15, y: 15, width: 10, height: 10 });
        
        tree.insert(rect1);
        tree.insert(rect2);
        tree.insert(rect3);
        
        // 查询附近的对象
        const nearby = tree.retrieve(rect1);
        Log.ecs.info(`rect1 附近的对象数量: ${nearby.length}`);
    }
    
    /**
     * 示例 2: 圆形碰撞检测
     */
    static example2_Circles(): void {
        Log.ecs.info('=== 示例 2: 圆形碰撞检测 ===');
        
        const tree = new Quadtree<Circle>({
            width: 100,
            height: 100
        });
        
        // 插入圆形
        for (let i = 0; i < 10; i++) {
            const circle = new Circle({
                x: Math.random() * 100,
                y: Math.random() * 100,
                r: 5 + Math.random() * 10,
                data: { id: i }
            });
            tree.insert(circle);
        }
        
        // 查询圆形
        const queryCircle = new Circle({ x: 50, y: 50, r: 20 });
        const nearby = tree.retrieve(queryCircle);
        Log.ecs.info(`查询圆附近的对象数量: ${nearby.length}`);
    }
    
    /**
     * 示例 3: 线段碰撞检测
     */
    static example3_Lines(): void {
        Log.ecs.info('=== 示例 3: 线段碰撞检测 ===');
        
        const tree = new Quadtree<Line>({
            width: 100,
            height: 100
        });
        
        // 插入线段
        const line1 = new Line({ x1: 0, y1: 0, x2: 50, y2: 50 });
        const line2 = new Line({ x1: 50, y1: 0, x2: 100, y2: 50 });
        const line3 = new Line({ x1: 25, y1: 25, x2: 75, y2: 75 });
        
        tree.insert(line1);
        tree.insert(line2);
        tree.insert(line3);
        
        // 查询线段
        const queryLine = new Line({ x1: 40, y1: 40, x2: 60, y2: 60 });
        const nearby = tree.retrieve(queryLine);
        Log.ecs.info(`查询线段附近的对象数量: ${nearby.length}`);
    }
    
    /**
     * 示例 4: 自定义数据类型
     */
    static example4_CustomData(): void {
        Log.ecs.info('=== 示例 4: 自定义数据类型 ===');
        
        interface PlayerData {
            name: string;
            health: number;
            score: number;
        }
        
        const tree = new Quadtree<Rectangle<PlayerData>>({
            width: 100,
            height: 100
        });
        
        // 插入带数据的矩形
        const player1 = new Rectangle<PlayerData>({
            x: 10,
            y: 10,
            width: 20,
            height: 20,
            data: { name: 'Player1', health: 100, score: 0 }
        });
        
        tree.insert(player1);
        
        // 访问自定义数据
        if (player1.data) {
            Log.ecs.info(`玩家: ${player1.data.name}, 生命值: ${player1.data.health}`);
        }
    }
    
    /**
     * 示例 5: 更新和移除对象
     */
    static example5_UpdateAndRemove(): void {
        Log.ecs.info('=== 示例 5: 更新和移除对象 ===');
        
        const tree = new Quadtree<Rectangle>({
            width: 100,
            height: 100,
            maxObjects: 1
        });
        
        const rect1 = new Rectangle({ x: 10, y: 10, width: 10, height: 10 });
        const rect2 = new Rectangle({ x: 50, y: 50, width: 10, height: 10 });
        
        tree.insert(rect1);
        tree.insert(rect2);
        
        Log.ecs.info(`插入后对象数量: ${tree.objects.length + tree.nodes.reduce((sum, n) => sum + n.objects.length, 0)}`);
        
        // 更新位置
        rect1.x = 80;
        rect1.y = 80;
        tree.update(rect1);
        
        Log.ecs.info('对象已更新');
        
        // 移除对象
        tree.remove(rect2);
        Log.ecs.info('对象已移除');
    }
    
    /**
     * 运行所有示例
     */
    static runAll(): void {
        this.example1_BasicRectangles();
        this.example2_Circles();
        this.example3_Lines();
        this.example4_CustomData();
        this.example5_UpdateAndRemove();
    }
}

